/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.gwt.apps.client.program;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;

import net.bioteam.appweb.gwt.apps.clientandserver.Constant;
import net.bioteam.appweb.model.Paragraph;
import net.bioteam.appweb.model.Parameter;
import net.bioteam.appweb.model.Program;
import net.bioteam.appweb.submit.ProgramValueBean;

import com.google.gwt.user.client.Window;
import com.smartgwt.client.types.Encoding;
import com.smartgwt.client.types.FormErrorOrientation;
import com.smartgwt.client.types.FormMethod;
import com.smartgwt.client.types.Overflow;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.CheckboxItem;
import com.smartgwt.client.widgets.form.fields.FloatItem;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
import com.smartgwt.client.widgets.form.fields.HiddenItem;
import com.smartgwt.client.widgets.form.fields.IntegerItem;
import com.smartgwt.client.widgets.form.fields.SectionItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.form.fields.UploadItem;
import com.smartgwt.client.widgets.form.validator.FloatRangeValidator;
import com.smartgwt.client.widgets.form.validator.IntegerRangeValidator;

public class ProgramForm extends DynamicForm
{
	ProgramValueBean bean;
	
	public final static  int CELL_WIDTH=250;
	public final static int titleWidth=300;
	public final static int iconHspace=20;
	public final static int DEFAULT_ICON_WIDTH=20;
	
	public final static String REQUIRED_SUFFIX="<em style='color:red;'>***</em>";
	public final static String CONDITIONAL_REQUIRED_SUFFIX="<em style='color:blue;'>***</em>";

	public ProgramForm()
	{
		setStyleName("programform");
		//setBorder("2px solid red");
		setEncoding(Encoding.MULTIPART);
		setTarget("__gwt_upload");
		setMethod(FormMethod.POST);
		setTitleWidth(300);
		setWidth100();
		//http://forums.smartclient.com/showthread.php?t=4026&highlight=DynamicForm+Height
		setOverflow(Overflow.AUTO);
		setCellBorder(5);
		setAction("apps/user/programhandler");
		setShowInlineErrors(true);
		setShowErrorText(true);
		
		setErrorOrientation(FormErrorOrientation.TOP);
		setRequiredTitleSuffix(REQUIRED_SUFFIX);
		setItemHoverWidth(300);
	}

	public ProgramValueBean getBean()
	{
		return bean;

		// action URL.
	}

	public void setBean(ProgramValueBean bean)
	{
		this.bean = bean;
		Program program = bean.getProgram();
		Window.setTitle(program.getName());
		
		
		
		FormItem fi = null;
		List<FormItem> items = new LinkedList<FormItem>();
		fi = new HiddenItem("_program");
		fi.setValue(program.getName());
		items.add(fi);

		fi = new HiddenItem(Constant.program_form_action_name);
		fi.setValue(Constant.run_action);
		items.add(fi);
		
		fi = new HiddenItem(Constant.progranm_form_cluster_name);
		fi.setValue("-1");
		items.add(fi);

		// this.

		for (Parameter param : program.getParameters())
		{
			if (param.isHidden())
			{
				String value = bean.getValue(param.getName());
				fi = new HiddenItem(param.getName());
				fi.setValue(value);
				items.add(fi);
			} else
			{
				switch (param.getType())
				{
				case BooleanType:
					items.add(addBooleanField(param, bean));
					break;
				case FloatType:
					items.add(addFloatField(param, bean));
					break;
				case IntegerType:
					items.add(addIntField(param, bean));
					break;
				case StringType:
				case OutputFileType:
					items.add(addStringField(param, bean));
					break;
				case InputFileType:
				case SequenceType:
					items.addAll(new MyDataItem(param, bean).getItems());
					break;
				case SingleSelectionType:
					items.add(addSelectionField(param, bean));
					break;
				case MultipleSelectionType:
					items.add(addMultiSelectionField(param, bean));
					break;
				case ParagraphType:
					Paragraph paragraph = (Paragraph) param;
					List<FormItem> rets = addParagraphField(paragraph);
					boolean hasVisibleElements = false;

					List<String> ids = new LinkedList<String>();
					for (FormItem item : rets)
					{
						if (!(item instanceof HiddenItem))
						{
							hasVisibleElements = true;
						}
						ids.add(item.getName());
					}

					if (!hasVisibleElements)
					{
						items.addAll(rets);
						break;
					}
					SectionItem si = new SectionItem();
					
					si.setDefaultValue(paragraph.getPrompt() == null ? paragraph.getName() : paragraph.getPrompt());
					si.setItemIds(ids.toArray(new String[0]));
					addInfoTooltip(si, param);
					si.setWidth(titleWidth + CELL_WIDTH);
					items.add(si);
					items.addAll(rets);
					break;
				}
			}
		}

		SectionItem si = new SectionItem();
		si.setDefaultValue("Extra Parameters");
		List<FormItem> rets = addExtraParameters(bean);
		List<String> ids = new LinkedList<String>();
		for (FormItem item : rets)
		{
			ids.add(item.getName());
		}
		si.setItemIds(ids.toArray(new String[0]));
		si.setWidth(titleWidth+CELL_WIDTH);
		items.add(si);
		items.addAll(rets);

//		for(FormItem item: items)
//		{
//			if (this.getField(item.getName())!=null)
//			//if (item.getValue()!=null || item.getValue().toString()!=null )
//			{
//				clearValue(item.getName());
//			}
//		}
		setFields(items.toArray(new FormItem[0]));
		//workaround: http://code.google.com/p/smartgwt/issues/detail?id=170

//		for (FormItem item : items)
//		{
//			if (item instanceof HiddenItem)
//			{
//				if (item.getName().equals("_program"))
//				{
//					setValue(item.getName(), program.getName());
//				} else
//				{
//					setValue(item.getName(), bean.getValue(item.getName()));
//				}
//			}
//		}
	}

	public static List<FormItem> addExtraParameters(ProgramValueBean bean)
	{
		SectionItem fs = new SectionItem();
		List<FormItem> items = new LinkedList<FormItem>();
		// add extra fields.
		Program p = bean.getProgram();
		for (net.bioteam.appweb.model.meta.Entry entry : p.getMetaData().values())
		{
			if (!entry.isDisplay())
			{
				continue;
			}
			TextItem tf = new TextItem(entry.getName());
			tf.setWidth(CELL_WIDTH);
			tf.setTitle(entry.getPrompt());
			String value = bean.getValue(entry.getName());
			if (value != null)
			{
				tf.setDefaultValue(value);
			}
			if (entry.getName().equals(Constant.email_key))
			{
				// TODO
				// tf.setVtype(VType.EMAIL);
			}
			items.add(tf);
		}
		// first add 10 files
		for (int i = 1; i <= 10; i++)
		{
			UploadItem tf = new UploadItem("_infile" + i);
			tf.setTitle("Input File " + i);
			tf.setWidth(CELL_WIDTH);
			items.add(tf);
		}

		return items;
	}

	public FormItem addBooleanField(Parameter param, ProgramValueBean bean)
	{

	

		String title=param.getPrompt() == null ? param.getName() : param.getPrompt();
		
		CheckboxItem cb = new CheckboxItem(param.getName());
		cb.setTitle(title);
		cb.setShowLabel(false);
		cb.setShowTitle(true);
		cb.setTitleOrientation(TitleOrientation.LEFT);
		cb.setLabelAsTitle(true);
		cb.setWidth(CELL_WIDTH);

		String value = bean.getValue(param.getName());
		if (value != null && value.equals("1"))
		{
			cb.setDefaultValue(true);
		} else
		{
			cb.setDefaultValue(false);
		}
		addInfoTooltip(cb, param);
		return cb;
	}

	public FloatItem addFloatField(Parameter param, ProgramValueBean bean)
	{
		FloatItem nf = new FloatItem();
		preField(nf, param, bean);
		FloatRangeValidator frv = new FloatRangeValidator();

		if (param.getScalemax() != null)
		{
			frv.setMax(Float.parseFloat(param.getScalemax().getValue()));
		}
		if (param.getScalemin() != null)
		{
			frv.setMin(Float.parseFloat(param.getScalemin().getValue()));
		}
		if (param.getScalemax() != null || param.getScalemin() != null)
		{
			nf.setValidators(frv);
		}
		addInfoTooltip(nf, param);
		return nf;
	}

	public IntegerItem addIntField(Parameter param, ProgramValueBean bean)
	{
		IntegerItem nf = new IntegerItem();
		preField(nf, param, bean);
		IntegerRangeValidator irv = new IntegerRangeValidator();
		if (param.getScalemax() != null)
		{
			// TODO number field can not handle float number
			irv.setMax(Integer.parseInt(param.getScalemax().getValue()));
		}
		if (param.getScalemin() != null)
		{
			irv.setMin(Integer.parseInt(param.getScalemin().getValue()));
		}
		if (param.getScalemax() != null || param.getScalemin() != null)
		{
			nf.setValidators(irv);
		}
		addInfoTooltip(nf, param);
		return nf;
	}

	public  TextItem addStringField(Parameter param, ProgramValueBean bean)
	{
		TextItem tf = new TextItem();
		preField(tf, param, bean);
		addInfoTooltip(tf, param);
		return tf;
	}

	public  void preField(FormItem field, Parameter param, ProgramValueBean bean)
	{
		String title = param.getPrompt() == null ? param.getName() : param.getPrompt();
		field.setName(param.getName());
		String value = bean.getValue(param.getName());
		if (param.isMandatory() && param.getDeaultValue() == null)
		{
			if (param.getPrecond() != null)
			{
				title += CONDITIONAL_REQUIRED_SUFFIX;
			} else
			{
				field.setRequired(true);
			}
		}
		if (value != null)
		{
			field.setDefaultValue(value);
		}
		field.setTitle(title);
		field.setWidth(CELL_WIDTH);
	}

	public  SelectItem addSelectionField(Parameter param, ProgramValueBean bean)
	{

		SelectItem cb = new SelectItem();
		cb.setWidth(CELL_WIDTH);
		cb.setName(param.getName());
		cb.setMultiple(false);
		cb.setDefaultToFirstOption(false);

		String title = param.getPrompt() == null ? param.getName() : param.getPrompt();

		String labels[];
		String values[];
		if (param.getVlist() != null)
		{
			labels = param.getVlist().getLabel().toArray(new String[0]);
			values = param.getVlist().getValue().toArray(new String[0]);
		} else
		{
			labels = new String[0];
			values = new String[0];
		}

		LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
		String[][] data = new String[labels.length][2];
		for (int i = 0; i < labels.length; i++)
		{
			valueMap.put(values[i], labels[i]);
		}
		cb.setValueMap(valueMap);

		String value = bean.getValue(param.getName());
		if (value != null && param.getVlist().getValue().contains(value))
		{
			cb.setDefaultValue(value);
		} else
		{
			cb.setEmptyDisplayValue("Please select ...");
		}
		if (param.isMandatory() && param.getDeaultValue() == null)
		{
			if (param.getPrecond() != null)
			{
				title += "<em style='color:blue;'>***</em>";
			} else
			{
				cb.setRequired(true);
				title += "<em style='color:red;'>***</em>";
			}
		}
		cb.setTitle(title);
		addInfoTooltip(cb, param);
		return cb;
	}

	public SelectItem addMultiSelectionField(Parameter param, ProgramValueBean bean)
	{

		SelectItem cb = new SelectItem();
		cb.setWidth(CELL_WIDTH);
		cb.setName(param.getName());
		cb.setMultiple(true);
		cb.setDefaultToFirstOption(false);

		String title = param.getPrompt() == null ? param.getName() : param.getPrompt();
		String labels[];
		String values[];
		if (param.getVlist() != null)
		{
			labels = param.getVlist().getLabel().toArray(new String[0]);
			values = param.getVlist().getValue().toArray(new String[0]);
		} else
		{
			labels = new String[0];
			values = new String[0];
		}

		LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>();
		for (int i = 0; i < labels.length; i++)
		{
			valueMap.put( values[i], labels[i]);
		}
		cb.setValueMap(valueMap);
		
		String value = bean.getValue(param.getName());
		if (value != null)
		{
			String separator = param.getSeparator();
			String[] values1=value.split(separator);
			//TODO use the setDefaultValues(...)
			//value=value.replaceAll( separator, ",");
			//cb.setDefaultValue(value);
			cb.setDefaultValues(values1);

		} else
		{
			cb.setEmptyDisplayValue("Please select ...");
		}
		if (param.isMandatory() && param.getDeaultValue() == null)
		{
			if (param.getPrecond() != null)
			{
				title += "<em style='color:blue;'>***</em>";
			} else
			{
				cb.setRequired(true);
				title += "<em style='color:red;'>***</em>";
			}

		}
		cb.setTitle(title);
		addInfoTooltip(cb, param);
		return cb;
	}

	protected List<FormItem> addParagraphField(Paragraph paragraph)
	{

		List<FormItem> rets = new LinkedList<FormItem>();
		for (Parameter param : paragraph.getParameters())
		{
			if (param.isHidden())
			{
				String value = bean.getValue(param.getName());
				HiddenItem hi = new HiddenItem(param.getName());
				hi.setValue(value);
				rets.add(hi);
			} else
			{
				switch (param.getType())
				{
				case BooleanType:
					rets.add(addBooleanField(param, bean));
					break;
				case FloatType:
					rets.add(addFloatField(param, bean));
					break;
				case IntegerType:
					rets.add(addIntField(param, bean));
					break;
				case StringType:
				case OutputFileType:
					rets.add(addStringField(param, bean));
					break;
				case InputFileType:
				case SequenceType:
					rets.addAll(new MyDataItem(param, bean).getItems());
					break;
				case SingleSelectionType:
					rets.add(addSelectionField(param, bean));
					break;
				case MultipleSelectionType:
					rets.add(addMultiSelectionField(param, bean));
					break;
				case ParagraphType:
					rets.addAll(addParagraphField((Paragraph) param));
					break;
				}
			}
		}
		return rets;
	}

	public static void addInfoTooltip(FormItem field, Parameter param)
	{

		if (param.getComment() == null || param.getComment().getValue() == null || param.getComment().getValue().size() == 0)
		{
			return;
		}

		List<String> comments = param.getComment().getValue();
		StringBuffer sb = new StringBuffer();
		for (String comment : comments)
		{
			sb.append("<p>" + comment + "</p>");
		}
		FormItemIcon icon = new FormItemIcon();
		icon.setSrc("[SKIN]/actions/help.png");
		field.setIcons(icon);
		field.setIconPrompt(sb.toString());
		field.setAttribute("iconHSpace", iconHspace);
		field.setWidth(CELL_WIDTH+DEFAULT_ICON_WIDTH+iconHspace);
		
	}
	
	
}
